#include "GameInput.h"
#include "GameGUI.h"

GameInput::GameInput(Ogre::RenderWindow *rw)
{
	OIS::ParamList pl;
	size_t windowHnd = 0;
	std::ostringstream windowHndStr;
 
	rw->getCustomAttribute("WINDOW", &windowHnd);
	windowHndStr << windowHnd;
	pl.insert(std::make_pair(std::string("WINDOW"), windowHndStr.str()));
 
	mpInputManager = OIS::InputManager::createInputSystem(pl);

	mpKeyboard = static_cast<OIS::Keyboard*>(mpInputManager->createInputObject(OIS::OISKeyboard, true));
	mpMouse = static_cast<OIS::Mouse*>(mpInputManager->createInputObject(OIS::OISMouse, true));
	//init lists
	for(unsigned int i = 0; i < NUMBER_KEYS; i++)
	{
		mKeyInputs[i] = InputInfo();
	}
	for(unsigned int i = 0; i < NUMBER_BUTTONS; i++)
	{
		mMouseInputs[i] = InputInfo();
	}
	mpMouse->setEventCallback(this);
	mpKeyboard->setEventCallback(this);
}


GameInput::~GameInput(void)
{
	
    mpInputManager->destroyInputObject(mpMouse);
    mpInputManager->destroyInputObject(mpKeyboard);
 
    OIS::InputManager::destroyInputSystem(mpInputManager);
    mpInputManager = 0;
}

OIS::Mouse *GameInput::getMouse(void)
{
	return mpMouse;
}


//KEYBOARD BEHAVIOUR
bool GameInput::keyPressed(const OIS::KeyEvent& evt)
{
	switch(mKeyInputs[evt.key].mState)
	{
	case RELEASED:
		mPressedList.push_back(evt.key);
		mKeyInputs[evt.key].mState = JUST_PRESSED;
		mKeyInputs[evt.key].mOrder = mPressedList.size()-1;
		break;
	case JUST_RELEASED:
		mPressedList.push_back(evt.key);
		mReleasedList.remove(evt.key);
		mKeyInputs[evt.key].mState = JUST_PRESSED;
		mKeyInputs[evt.key].mOrder = mPressedList.size()-1;
	}
	keyPressedCommand(evt);

	// Send input information to the GUI
	CEGUI::System &sys = CEGUI::System::getSingleton();
	sys.injectKeyDown(evt.key);
	sys.injectChar(evt.text);
	if (gpGUI) gpGUI->onGlobalCharacterKey(evt.key);
	
	return true;
}

bool GameInput::keyReleased(const OIS::KeyEvent& evt)
{
	if(mKeyInputs[evt.key].mState == JUST_PRESSED || mKeyInputs[evt.key].mState == PRESSED )
	{
		mReleasedList.push_back(evt.key);
		mPressedList.remove(evt.key);
		mKeyInputs[evt.key].mState = JUST_RELEASED;
		mKeyInputs[evt.key].mOrder = -1;
		updateOrder();
	}
	keyReleasedCommand(evt);

	// Send input information to the GUI
	CEGUI::System::getSingleton().injectKeyUp(evt.key);

	return true;
}

inline void GameInput::keyReleasedCommand(const OIS::KeyEvent& evt)
{
}

inline void GameInput::keyPressedCommand(const OIS::KeyEvent& evt)
{
}

//MOUSE BEHAVIOUR

inline CEGUI::MouseButton convertButton(OIS::MouseButtonID buttonID)
{
    switch (buttonID)
    {
    case OIS::MB_Left:
        return CEGUI::LeftButton;
 
    case OIS::MB_Right:
        return CEGUI::RightButton;
 
    case OIS::MB_Middle:
        return CEGUI::MiddleButton;
 
    default:
        return CEGUI::LeftButton;
    }
}

bool GameInput::mousePressed(const OIS::MouseEvent& evt, OIS::MouseButtonID id)
{
	mMouseState = evt.state;
	mMouseInputs[id].mState = JUST_PRESSED;
	mousePressedCommand(evt, id);

	// Send input information to the GUI
	CEGUI::System::getSingleton().injectMouseButtonDown(convertButton(id));

	return true;
}

bool GameInput::mouseReleased(const OIS::MouseEvent& evt, OIS::MouseButtonID id)
{
	mMouseState = evt.state;
	mMouseInputs[id].mState = JUST_RELEASED;
	mouseReleasedCommand(evt, id);

	// Send input information to the GUI
	CEGUI::System::getSingleton().injectMouseButtonUp(convertButton(id));

	return true;
}

bool GameInput::mouseMoved(const OIS::MouseEvent& evt)
{
	mMouseState = evt.state;
	mouseMovedCommand(evt);
	
	// Send input information to the GUI
	CEGUI::System &sys = CEGUI::System::getSingleton();
	sys.injectMouseMove((float)evt.state.X.rel, (float)evt.state.Y.rel);
	// Scroll wheel.
	if (evt.state.Z.rel)
	    sys.injectMouseWheelChange(evt.state.Z.rel / 120.0f);

	return true;
}

inline void GameInput::mousePressedCommand(const OIS::MouseEvent& evt, OIS::MouseButtonID id)
{
	return;
}

inline void GameInput::mouseReleasedCommand(const OIS::MouseEvent& evt, OIS::MouseButtonID id)
{
	return;
}

inline void GameInput::mouseMovedCommand(const OIS::MouseEvent& evt)
{
	return;
}

//UPDATING THE INPUT
void GameInput::updateInput(void)
{
	for (ButtonList::iterator it = mPressedList.begin(); it != mPressedList.end(); ++it)
	{
		mKeyInputs[(*it)].mState = PRESSED;
	}
	for (ButtonList::iterator it = mReleasedList.begin(); it != mReleasedList.end(); ++it)
	{
		mKeyInputs[(*it)].mState = RELEASED;
	}
	mReleasedList.clear();
	
	for(unsigned int i = 0; i < NUMBER_BUTTONS; ++i)
	{
		switch(mMouseInputs[i].mState)
		{
		case JUST_PRESSED:
			mMouseInputs[i].mState = PRESSED;
			break;
		case JUST_RELEASED:
			mMouseInputs[i].mState = RELEASED;
		}
	}
	mpKeyboard->capture();
	mpMouse->capture();
}
void GameInput::updateOrder(void)
{
	unsigned int i = 0;
	for (ButtonList::iterator it = mPressedList.begin(); it != mPressedList.end(); ++it)
	{
		mKeyInputs[(*it)].mOrder = i++;
	}
}

//INTERFACING
InputInfo *GameInput::getKeyInputs(void)
{
	return mKeyInputs;
}

InputInfo *GameInput::getMouseInputs(void)
{
	return mMouseInputs;
}

OIS::MouseState GameInput::getMouseState(void)
{
	return mMouseState;
}